package graph;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

import entity.Poker;
import model.GameModel;
import model.VictoryModel;
import model.VictoryPoker;
import tool.GraphToModel;
import tool.PlayMusic;
import tool.ReadResources;

public class PaintPanel extends JPanel implements MouseListener,MouseMotionListener{
	class OffSet{	//鼠标偏移量
		int x;	//横坐标偏移
		int y;	//纵坐标偏移
		public OffSet() {
			// TODO Auto-generated constructor stub
			this.x=0;
			this.y=0;
		}
	}
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static int MIN_WIDTH=900;
	private static int MIN_HEIGHT=720;//最小高、宽
	private static int MIN_HOR_SPLIT=51;//最小分割
	private static int MIN_VER_SPLIT=45;//
	private static int MIN_CARD_WIDTH=70;//
	private static int MIN_CARD_HEIGHT=100;
	private GameModel gamemodel;//游戏模型
	private int curHeight;//当前高度
	private int curWidth;
	private int horSplit;//水平间隙
	private int verSplit;//竖直间隙
	private int cardHeight;//牌的高度
	private int cardWidth;//牌的宽度
	private VictoryModel victoryModel;
	private ReadResources readPoker;//扑克读取工具
	private GraphToModel graphToModel;//图像模型数值转换工具
	private OffSet offset;//坐标偏移
	private int curX;	//当前的X
	private int curY;	//当前的Y
	private String lastPile;//上一个接触的牌堆
	private PlayMusic playMusic;
	public PaintPanel(GameModel model,ReadResources readPoker) {
		// TODO Auto-generated constructor stub
		this.gamemodel=model;
		this.horSplit=51;
		this.verSplit=45;
		this.cardHeight=100;
		this.cardWidth=70;
		addMouseListener(this);
		addMouseMotionListener(this);
		this.readPoker=readPoker;//读取扑克
		graphToModel=new GraphToModel(horSplit, verSplit, cardWidth,cardHeight);
		offset=new OffSet();//新建偏移量
		curX=-1;//此时鼠标没有指向任何东西
		curY=-1;
		lastPile="null";
		curHeight=720;
		curWidth=900;
		playMusic=new PlayMusic();
		victoryModel=new VictoryModel(curWidth, curHeight,cardHeight);
	}
	/**重置画板大小
	 * 
	 * @param height 高度
	 * @param width 宽度
	 */
	public boolean reSizePaint(int height,int width){
		if(height<MIN_HEIGHT||width<MIN_WIDTH)
			return false;
		double scale=0;
		scale=height*1.0/curHeight;//计算放大比例
		cardHeight=(int) (cardHeight*scale);
		cardWidth=(int) (cardWidth*scale);//计算新的牌大小
		verSplit=(int) (verSplit*scale);//计算新的竖直分割大小
		horSplit=(width-7*cardWidth)/8;//水平方向除了牌之外剩下的都分给分割
		cardWidth=cardWidth<MIN_CARD_WIDTH?MIN_CARD_WIDTH:cardWidth;
		cardHeight=cardHeight<MIN_CARD_HEIGHT?MIN_CARD_HEIGHT:cardHeight;
		horSplit=horSplit<MIN_HOR_SPLIT?MIN_HOR_SPLIT:horSplit;
		verSplit=verSplit<MIN_VER_SPLIT?MIN_VER_SPLIT:verSplit;
		curHeight=height;
		graphToModel.updateParam(horSplit, verSplit, cardWidth, cardHeight);
		victoryModel.updateParams(width, height, cardHeight);
		return true;
	}
	/**画基线
	 * 
	 * @param g2
	 */
	private void drawBaseLine(Graphics2D g2){
		g2.setColor(Color.BLACK);//设置白色
		g2.drawRect(horSplit, verSplit, cardWidth, cardHeight);//绘制deck基线
		int start=horSplit*4+cardWidth*3;//先跳过discard的基线
		for(int i=0;i<4;i++){	//绘制suitpile基线
			g2.drawRect(start, verSplit, cardWidth, cardHeight);
			start+=cardWidth+horSplit;//偏移一个牌宽和一个横向间隔
		}
		start=horSplit;//跳到第一个牌堆的位置
		for(int i=0;i<7;i++){	//绘制SevPile基线
			g2.drawRect(start, verSplit*2+cardHeight, cardWidth, cardHeight);
			start+=cardWidth+horSplit;//偏移一个牌宽和一个横向间隔
		}
	}
	/**绘制背景
	 * 
	 * @param g2
	 */
	private void drawBackground(Graphics2D g2){
		g2.drawImage(readPoker.getTabelBack(),0, 0, this.getWidth(), this.getHeight(), this);
		//g2.setColor(Color.GREEN);	//设置背景为绿色
		//g2.fill(new Rectangle2D.Double(0, 0, this.getWidth(), this.getHeight()));
	}
	/**绘制一张扑克
	 * 
	 * @param g2
	 * @param p 扑克
	 * @param x 横坐标
	 * @param y 纵坐标
	 * @param w 宽
	 * @param h 高
	 */
	private void drawPoker(Graphics2D g2,Poker p,int x,int y,int w,int h){
		g2.drawImage(readPoker.getPoker(p.getSuit(),p.getNumber()),x, y, w,h, this);
	}
	/**绘制deck
	 * 
	 * @param g2
	 */
	private void drawDeck(Graphics2D g2){
		g2.setColor(Color.GREEN);//正式版本这里应该放牌背面
		if(!gamemodel.isDeckEmpty())	//如果Deck不为空
			g2.drawImage(readPoker.getPokerBack(), horSplit, verSplit, cardWidth, cardHeight, this);
		else
			return;
		graphToModel.updateScope("dec",horSplit, verSplit, cardWidth, cardHeight);//更新范围
		//scopeMap.put("dec",new Scope());//增加一个范围
	}
	/**绘制SuitPile
	 * 
	 * @param g2
	 */
	private void drawSuitPile(Graphics2D g2){
		int start=horSplit*4+cardWidth*3;	//跳到suitpile起始位置
		for(int i=0;i<4;i++){	//绘制四次
			Poker pok=gamemodel.getSuitPileTop(i);	//获取每一个suitpile顶部的扑克
			if(pok!=null){	//如果顶部有扑克
				drawPoker(g2, pok, start, verSplit, cardWidth, cardHeight);
				//g2.fillRect(start, verSplit, cardWidth, cardHeight);	//绘制信息
			}
			graphToModel.updateScope(new StringBuffer("sui").append(i).toString(),start, verSplit, cardWidth, cardHeight);//更新范围
			//scopeMap.put(new StringBuffer("sui").append(i).toString(), new Scope());
			start+=horSplit+cardWidth;	//进行偏移
		}
	}
	/**绘制一个SevPile牌堆
	 * 
	 * @param g2
	 * @param n 序号
	 */
	private void drawOneSevPile(Graphics2D g2,int n){
		int start=verSplit*2+cardHeight;//跳到起始高度
		List<Poker> pokers=gamemodel.getSevPokers(n);//获取该堆的所有扑克
		for(Poker poker:pokers){	//依次绘制扑克
			if(poker.isUp()){
				drawPoker(g2, poker, (n+1)*horSplit+n*cardWidth, start, cardWidth, cardHeight);
				g2.setColor(Color.BLACK);
				g2.drawRect((n+1)*horSplit+n*cardWidth, start, cardWidth, cardHeight);
				start+=cardHeight/10*3;
			}else{
				g2.drawImage(readPoker.getPokerBack(),(n+1)*horSplit+n*cardWidth, start, cardWidth, cardHeight, this);
				g2.setColor(Color.BLACK);
				g2.drawRect((n+1)*horSplit+n*cardWidth, start, cardWidth, cardHeight);
				start+=cardHeight/10;
			}
		}
		start-=verSplit*2+cardHeight/10*3;//偏移到该牌堆尾部
		graphToModel.updateScope(new StringBuffer("sev").append(n).toString(),(n+1)*horSplit+n*cardWidth,verSplit*2+cardHeight, cardWidth, start);//更新范围
	}
	/**绘制7个SevPile牌堆
	 * 
	 * @param g2
	 */
	private void drawSevPiles(Graphics2D g2){
		for(int i=0;i<7;i++){	//绘制七次
			drawOneSevPile(g2, i);
		}
	}
	/**绘制Discard
	 * 
	 * @param g2
	 */
	private void drawDiscard(Graphics2D g2){
		List<Poker> pokers=gamemodel.getCurDiscard();
		int start=horSplit*2+cardWidth;
		for(Poker poker:pokers){
				drawPoker(g2, poker, start, verSplit, cardWidth, cardHeight);
				g2.setColor(Color.BLACK);
				g2.drawRect(start, verSplit, cardWidth, cardHeight);
				start+=cardWidth/7*2;
		}
		start-=horSplit*2+cardWidth/7*2;
		graphToModel.updateScope("dis",horSplit*2+cardWidth, verSplit, start, pokers.isEmpty()?0:cardHeight);//更新范围
		//scopeMap.put(, new Scope();//设置dis域
	}
	/**绘制手中的图画
	 * 
	 * @param g2
	 */
	private void drawHand(Graphics2D g2){
		if(curX==-1)
			return;
		List<Poker> pokers=gamemodel.getHandPokers();
		int start=curY-offset.y;//要绘制的起始纵坐标
		int x=curX-offset.x;//要绘制的纵坐标
		for(Poker poker:pokers){
			drawPoker(g2, poker, x, start, cardWidth, cardHeight);
			start+=cardHeight/10*3;//偏移
		}
	}
	/**在任意位置上画图
	 * 
	 * @param g2
	 */
	private void drawRandomPoker(Graphics2D g2){
		/*Random random=new Random();
		int x=random.nextInt(this.getWidth()), y=random.nextInt(this.getHeight());
		int degree=random.nextInt(360);
		//g2.setColor(Color.red);
		//g2.rotate(Math.toRadians(degree));
		g2.drawImage(readPoker.getPoker(Suit.values()[random.nextInt(4)],random.nextInt(13)+1),x, y, cardWidth,cardHeight, this);*/
		for(VictoryPoker poker:victoryModel.getPokers()){//遍历所有扑克
			//System.out.println(poker.y);
			drawPoker(g2, poker.poker, poker.x, poker.y, cardWidth, cardHeight);//绘制扑克
		}
	}
	/**实际绘制函数
	 * 
	 */
	public void paint(Graphics g){
		//System.out.println("重新绘制");
		super.paint(g);
		Graphics2D g2=(Graphics2D)g;	//转换成Graphics2D获取更多的绘画方式
		drawBackground(g2);//绘制背景
		drawBaseLine(g2);//绘制基线
		drawDeck(g2);//绘制deck堆
		drawSuitPile(g2);//绘制suitpiles堆
		drawSevPiles(g2);//绘制sevPiles堆
		drawDiscard(g2);//绘制Discard
		drawHand(g2);//绘制hand
		if(gamemodel.isWin()){	//动画绘制
			//for(int i=0;i<50;i++)
			drawRandomPoker(g2);
		}
	}
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		String str=graphToModel.getScopeName(e.getX(), e.getY());
		switch(str.substring(0,3)){
		case "dec"://按下Deck
			playMusic.playTurn();
			gamemodel.nextDiscard();
			break;
		case "sev":	//按下sev
			int id=(int)(str.charAt(3))-48;
			List<Poker> list=gamemodel.getSevPokers(id);
			if(graphToModel.isTop(e.getY(), list))
				gamemodel.upPoker(id);
			break;
		default:
			break;
		}
		repaint();
	}
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		if(gamemodel.isWin())	//如果该模型已经取得胜利
			return;		//返回
		String str=graphToModel.getScopeName(e.getX(), e.getY());
		int id;
		List<Poker> list;
		switch(str.substring(0,3)){
		case "sui"://按下SuitPiles
			id=(int)(str.charAt(3))-48;
			if(gamemodel.takeFromSuit(id)){
				playMusic.playClick();
					offset.x=e.getX()-(4*horSplit+3*cardWidth+id*(cardWidth+horSplit));
					offset.y=e.getY()-verSplit;
					curX=e.getX();
					curY=e.getY();
			}
			//System.out.println("按下SuitPiles");
			break;
		case "dis"://按下discard
			list=gamemodel.getCurDiscard();
			id=graphToModel.getIdFromDiscardPile(e.getX(), list);
			if(gamemodel.takeFromDiscard(id)){
				playMusic.playClick();
				offset.x=e.getX()-(2*horSplit+cardWidth+id*(cardWidth/7*2));
				offset.y=e.getY()-verSplit;
				curX=e.getX();
				curY=e.getY();
			}
			break;
		case "sev"://按下SevPiles
			id=(int)(str.charAt(3))-48;
			list=gamemodel.getSevPokers(id);
			int i=graphToModel.getIdFromSevPile(e.getY(), list);
			gamemodel.upPoker(id);
			if(gamemodel.takeFromSev(id, i)){
				playMusic.playClick();
				offset.x=e.getX()-horSplit-(horSplit+cardWidth)*id;	//算出鼠标横偏移
				offset.y=graphToModel.getSevOffSetY(e.getY(), id, i, list);
				curX=e.getX();
				curY=e.getY();
			}
			break;
		default:
			return;
		}
		lastPile=str;
		repaint();
	}
	@Override
	public void mouseReleased(MouseEvent e) {
		if(gamemodel.isWin())	//如果已经赢了
			return;
		curX=-1;//当前鼠标没有牌
		String str=graphToModel.getScopeName(e.getX(), e.getY());
		int id;
		if(!lastPile.equals(str)){
			switch(str.substring(0,3)){
			case "sui"://在suitPiles松手
				id=(int)(str.charAt(3))-48;
				gamemodel.putToSuit(id);
				break;
			case "sev"://按下SevPiles
				id=(int)(str.charAt(3))-48;
				gamemodel.putToSev(id);
				break;
			default:
				gamemodel.throwPokers();
				break;
			}
		}
		else{
			gamemodel.throwPokers();
		}
		//cacheModel.updateCache(gamemodel);
		repaint();
		if(gamemodel.isWin()){
			new Thread(new PassFruit(this, gamemodel)).start();
			//System.out.println("你赢了！");
			int result = JOptionPane.showConfirmDialog(this, "你赢了，是否再来一局？");
			if(result==0){
				gamemodel.refreshPokers();
				repaint();
			}
		}
		
		//System.out.println("完成");
	}
	@Override
	public void mouseEntered(MouseEvent e) {
		
	}
	@Override
	public void mouseExited(MouseEvent e) {
		
	}
	@Override
	public void mouseDragged(MouseEvent e) {
		if(curX!=-1){
			curX=e.getX();
			curY=e.getY();
			repaint();
		}
	}
	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub
	}
}
